/**
 * @Auther: ayo
 * @Date: 2018/8/20 16:57
 * @Description: 一个没描述的工具类
 */
import { Injectable } from '@angular/core';
// import * as CryptoJS from 'crypto-js';
import { CONFIG } from '../../app/app.config';

@Injectable()
export class Utils {

    constructor() {
    }

    /**
     * 每次调用sequence加1
     * @type {()=>number}
     */
    static getSequence = (
        function () {
            let sequence = 100;
            return function () {
                return ++sequence;
            };
        })();

    /**
     * 是否为空
     * @param value 值
     */
    static isEmpty(value: any): boolean {
        return value === undefined || value === null || typeof value === 'string' && value.length === 0;
    }

    /**
     * 是否不为空
     * @param value 值
     */
    static isNotEmpty(value: any): boolean {
        return !Utils.isEmpty(value);
    }

    /**
     * 格式“是”or“否”
     * @param value
     * @returns {string|string}
     */
    static formatYesOrNo(value: number | string): string {
        return value === 1 || value === '1' ? '是' : (
            value === 0 || value === '0' ? '否' : null);
    }


    /**
     * 是否数组
     * @param value 值
     */
    static isArray(value: any): boolean {
        return Array.isArray(value);
    }

    /**
     * 是否对象
     * @param value 值
     */
    static isObject(value: any): boolean {
        return typeof value === 'object' && !Utils.isArray(value);
    }

    /**
     * url中如果有双斜杠替换为单斜杠
     * @param url
     * @returns {string}
     */
    static replaceUrl(url) {
        return 'http://' + url.substring(7).replace(/\/\//g, '/');
    }

    /**
     * 日期对象转为日期字符串
     * @param date 需要格式化的日期对象
     * @param sFormat 输出格式,默认为yyyy-MM-dd                         年：y，月：M，日：d，时：h，分：m，秒：s
     * @example  dateFormat(new Date())                               "2017-02-28"
     * @example  dateFormat(new Date(),'yyyy-MM-dd')                  "2017-02-28"
     * @example  dateFormat(new Date(),'yyyy-MM-dd hh:mm:ss')         "2017-02-28 09:24:00"
     * @example  dateFormat(new Date(),'hh:mm')                       "09:24"
     * @example  dateFormat(new Date(),'yyyy-MM-ddThh:mm:ss+08:00')   "2017-02-28T09:24:00+08:00"
     * @returns {string}
     */
    static dateFormat(date: Date, sFormat: String = 'yyyy-MM-dd'): string {
        const time = {
            Year: 0,
            TYear: '0',
            Month: 0,
            TMonth: '0',
            Day: 0,
            TDay: '0',
            Hour: 0,
            THour: '0',
            hour: 0,
            Thour: '0',
            Minute: 0,
            TMinute: '0',
            Second: 0,
            TSecond: '0',
            Millisecond: 0
        };
        time.Year = date.getFullYear();
        time.TYear = String(time.Year).substr(2);
        time.Month = date.getMonth() + 1;
        time.TMonth = time.Month < 10 ? '0' + time.Month : String(time.Month);
        time.Day = date.getDate();
        time.TDay = time.Day < 10 ? '0' + time.Day : String(time.Day);
        time.Hour = date.getHours();
        time.THour = time.Hour < 10 ? '0' + time.Hour : String(time.Hour);
        time.hour = time.Hour < 13 ? time.Hour : time.Hour - 12;
        time.Thour = time.hour < 10 ? '0' + time.hour : String(time.hour);
        time.Minute = date.getMinutes();
        time.TMinute = time.Minute < 10 ? '0' + time.Minute : String(time.Minute);
        time.Second = date.getSeconds();
        time.TSecond = time.Second < 10 ? '0' + time.Second : String(time.Second);
        time.Millisecond = date.getMilliseconds();

        return sFormat.replace(/yyyy/ig, String(time.Year))
                      .replace(/yyy/ig, String(time.Year))
                      .replace(/yy/ig, time.TYear)
                      .replace(/y/ig, time.TYear)
                      .replace(/MM/g, time.TMonth)
                      .replace(/M/g, String(time.Month))
                      .replace(/dd/ig, time.TDay)
                      .replace(/d/ig, String(time.Day))
                      .replace(/HH/g, time.THour)
                      .replace(/H/g, String(time.Hour))
                      .replace(/hh/g, time.Thour)
                      .replace(/h/g, String(time.hour))
                      .replace(/mm/g, time.TMinute)
                      .replace(/m/g, String(time.Minute))
                      .replace(/ss/ig, time.TSecond)
                      .replace(/s/ig, String(time.Second))
                      .replace(/fff/ig, String(time.Millisecond));
    }

    /**
     *  UUID生成
     *  @returns {string}
     */
    static UUID(): string {
        return 'xxxxxxxx-xxxx-6xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
            const r = Math.random() * 16 | 0, v = c === 'x' ? r : (
                r & 0x3 | 0x8);
            return v.toString(16);
        });
    }

    /**
     *  短UUID生成
     *  @returns {string}
     */
    static shortUUID(): string {
        return 'xx-6xy'.replace(/[xy]/g, function (c) {
            const r = Math.random() * 16 | 0, v = c === 'x' ? r : (
                r & 0x3 | 0x8);
            return v.toString(6);
        });
    }

    // 随机数
    static getRandomCode(_prefix) {
        return new Utils().guid(_prefix);
    }

    /**
     * @Author: ayo
     * @Date: 2018/9/29 14:31
     * @Param:
     * @return:
     * @Description: // JSON拼接
     **/
    arrayMappingFilter = (array: Array<any>, key, value) => {
        const tempArray = {};
        array.forEach(item => {
            tempArray[item[key]] = item[value];
        });
        return tempArray;
    };
    /**
     * @Author: ayo
     * @Date: 2018/10/5 17:18
     * @Param:
     * @return:
     * @Description: // 用于替换字符串{key}中的key
     **/
    replaceParamKey = (url, pathVariables) => {
        if (Utils.isNotEmpty(pathVariables)) {
            for (const key in pathVariables) {
                if (pathVariables.hasOwnProperty(key)) {
                    switch (key) {
                        case key:
                            url = url.replace('{' + key + '}', pathVariables[key]);
                            break;
                        default:
                            break;
                    }
                }
            }
            return url;
        }
    };
    /**
     * @Author: ayo
     * @Date: 2018/10/5 17:18
     * @Param:
     * @return:
     * @Description: // 用于拼接url
     **/
    increaseParams = (url, params, symbol) => {
        if (Utils.isNotEmpty(params)) {
            const param = [];
            for (const key in params) {
                if (params.hasOwnProperty(key)) {
                    switch (key) {
                        case key:
                            param.push(key + '=' + params[key]);
                            break;
                        default:
                            break;
                    }
                }
            }
            url = url + symbol + param.join('&');
            return url;
        }
    };

    gmtConvertToISO(date: Date) {
        return new Date(date.getTime() + 8 * 3600 * 1000).toISOString();
    }

    isoConvertToGmt(date: Date) {
        return new Date(date.getTime() - 8 * 3600 * 1000);
    }

    getCardsModelNameByKey(cards, index, key) {
        const items = cards[Number(index)]['items'];
        const result = items.find(i => i.lookupCode === key) || {};
        return result.modelName ? result['modelName'] : null;
    }

    getCardsItemByKey(cards, index, key) {
        const items = cards[Number(index)]['items'];
        const result = items.find(i => i.lookupCode === key) || {};
        return result ? result : [];
    }

    getCardsModelNameParamsByList(params, cards) {
        const result = {};
        if (Utils.isNotEmpty(params)) {
            params.map((item) => {
                cards.map((i, index) => {
                    const tempItem = this.getCardsItemByKey(cards, index, item.key);
                    if (tempItem.lookupCode) {
                        switch (item.symbol) {
                            case 'modelName':
                                result[item.key] = tempItem.modelName;
                                break;
                            case 'keyMap':
                                // ['1', '2'] -> '1,2'
                                result[item.key] = tempItem.modelName ? tempItem.modelName.join(',') : null;
                                break;
                            case 'valueMap':
                                // 1 -> value1
                                // ['1', '2'] -> 'value1,value2'
                                result[item.mayKey] = Array.isArray(tempItem.modelName) ? tempItem.modelName.map(
                                    (modelItem) => tempItem.options.find(innerI => innerI.value === modelItem).name).join() :
                                                      Utils.isNotEmpty(tempItem.modelName) ?
                                                      tempItem.options.find(innerI => innerI.value === tempItem.modelName).label : null;
                                break;
                            default:
                                break;
                        }
                    }
                });
            });
        }
        return result;
    }

    randomId() {
        return (
            (
                (
                    1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
    }

    // encrypt(word) {
    //     const key = CryptoJS.enc.Utf8.parse(CONFIG.BASIC_CONFIGS.AES_KEY);
    //     const srcs = CryptoJS.enc.Utf8.parse(word);
    //     const encrypted = CryptoJS.AES.encrypt(srcs, key, {
    //         mode: CryptoJS.mode.ECB,
    //         padding: CryptoJS.pad.Pkcs7
    //     });
    //     return encrypted.toString();
    // }
    //
    // decrypt(word) {
    //     const key = CryptoJS.enc.Utf8.parse(CONFIG.BASIC_CONFIGS.AES_KEY);
    //     const decrypt = CryptoJS.AES.decrypt(word, key, {
    //         mode: CryptoJS.mode.ECB,
    //         padding: CryptoJS.pad.Pkcs7
    //     });
    //     return CryptoJS.enc.Utf8.stringify(decrypt).toString();
    // }

    guid(prefix: string) {
        return (
            prefix + '-' + this.randomId() + '-' + this.randomId() + '-' + this.randomId() + this.randomId() + this.randomId());
    }

    /**
     * @Author: ayo
     * @Date: 2019/12/17 10:35
     * @Param: yyyy-MM-dd(String)
     * @return: age(Number)
     * @Description: // 根据日期获取年龄
     **/
    getAge = (date) => {
        let returnAge;
        const birArr = date.split('-');
        const birYear = birArr[0];
        const birMonth = birArr[1];
        const birDay = birArr[2];
        const now = new Date();
        const nowYear = now.getFullYear();
        const nowMonth = now.getMonth() + 1;
        const nowDay = now.getDate();
        if (birArr == null) {
            return false;
        }
        const d = new Date(birYear, birMonth - 1, birDay);
        if (d.getFullYear() == birYear && (
            d.getMonth() + 1) == birMonth && d.getDate() == birDay) {
            if (nowYear == birYear) {
                returnAge = 0;
            } else {
                const ageDiff = nowYear - birYear;
                if (ageDiff > 0) {
                    if (nowMonth == birMonth) {
                        const dayDiff = nowDay - birDay;
                        if (dayDiff < 0) {
                            returnAge = ageDiff - 1;
                        } else {
                            returnAge = ageDiff;
                        }
                    } else {
                        const monthDiff = nowMonth - birMonth;
                        if (monthDiff < 0) {
                            returnAge = ageDiff - 1;
                        } else {
                            returnAge = ageDiff;
                        }
                    }
                } else {
                    return false;
                }
            }
            return returnAge;
        } else {
            return false;
        }
    };

    /**
     * 防抖函数
     * @param {Function} fn - 实际要执行的函数
     * @param {Number} time - 规定在什么时间内执行一次函数，单位是秒
     * @param {Boolean} immediate - 是否立即执行，true为立即执行，立即执行指触发监听事件是先执行
     */
    debounce(fn, time, immediate) {
        let timeout, result;

        return function () {
            const context = this;
            const args = arguments;

            if (timeout) clearTimeout(timeout);
            if (immediate) {
                // 如果已经执行过，不再执行
                const callNow = !timeout;
                timeout = setTimeout(function(){
                    timeout = null;
                }, time);
                if (callNow) result = fn.apply(context, args)
            }
            else {
                timeout = setTimeout(function(){
                    fn.apply(context, args)
                }, time);
            }
            return result;
        };
    }

    /**
     * 节流函数
     * @param {Function} fn - 实际要执行的函数，对其进行节流处理
     * @param {Number} time - 规定的执行时间间隔
     * @param {Object} options - 用于设置节流的函数的触发时机，
     *                        - 默认是{leading: true, trailing: true}，表示第一次触发监听事件马上执行，停止后最后也执行一次
     *                        - leading为false时，表示第一次触发不马上执行
     *                        - trailing为false时，表示最后停止触发后不执行
     */
    throttle(fn, time, options) {
        let timeout, context, args, result;
        let previous = 0;
        if (!options) options = {};

        const later = function() {
            previous = options.leading === false ? 0 : new Date().getTime();
            timeout = null;
            fn.apply(context, args);
            if (!timeout) context = args = null;
        };

        return function() {
            const now = new Date().getTime();
            if (!previous && options.leading === false) previous = now;
            const remaining = time - (now - previous);
            context = this;
            args = arguments;
            if (remaining <= 0 || remaining > time) {
                if (timeout) {
                    clearTimeout(timeout);
                    timeout = null;
                }
                previous = now;
                fn.apply(context, args);
                if (!timeout) context = args = null;
            } else if (!timeout && options.trailing !== false) {
                timeout = setTimeout(later, remaining);
            }
        };
    }
}
